#pragma once

#include <mutex>
#include <semaphore.h>
#include "Assisted.hpp"
#include "Abstract.hpp"
#include "DefinitionField.hpp"
#include "Message.hpp"
#include "../tcp/source/tcp_server.hpp"


namespace xu
{

    class ModuoBuffer : public BaseBuffer
    {
    public:
        using Ptr = std::shared_ptr<ModuoBuffer>;
        ModuoBuffer(Buffer *buf)
            : _buf(buf)
        {
        }
        // 查看缓冲区前4字节数据
        virtual int32_t PeekInt32() override
        {
            return _buf->PeekInt32();
        }

        // 缓冲区可读数据大小
        virtual size_t ReadableBytes() override
        {
            return _buf->ReadSize();
        }

        // 读4字节并删除
        virtual int32_t ReadIint32() override
        {
            return _buf->ReadIint32();
        }

        // 读取len字节数据
        virtual std::string RetrieveAsString(size_t len) override
        {
            return _buf->ReadStringPop(len);
        }

    private:
        Buffer *_buf;
    };

    class BufferFactory
    {
    public:
        template <typename... Args>
        static BaseBuffer::Ptr create(Args &&...args)
        {
            return std::make_shared<ModuoBuffer>(std::forward<Args>(args)...);
        }
    };


    class LvProtocol : public BaseProtocol
    {
    public:
        using Ptr = std::shared_ptr<LvProtocol>;

        // 通过buf设置mes
        virtual bool OnMessage(const BaseBuffer::Ptr &buf, BaseMessage::Ptr &msg) override
        {
            //|len|mtype|idlen|id|body|
            int len = ntohl(buf->ReadIint32());
            MType mtype = (MType)ntohl(buf->ReadIint32());
            int idlen =ntohl(buf->ReadIint32());
            std::string id = buf->RetrieveAsString(idlen);
            int bodylen = len - _mtlen - _idlen - idlen;
            std::string body = buf->RetrieveAsString(bodylen);

            msg = MessageFactory::create(mtype);

            if (msg.get() == nullptr)
            {
                LOG(LogLevel::ERROR) << "类型错误导致创建失败";
                return false;
            }

            msg->SetId(id);
            msg->SetMType(mtype);
            bool ret = msg->Deserialization(body);
            if (ret == false)
            {
                LOG(LogLevel::ERROR) << "反序列失败";
                return false;
            }

            return true;
        }

        // 能否取出一个完整的数据
        virtual bool CanProcessed(const BaseBuffer::Ptr &buf) override
        {
            if (buf->ReadableBytes() < _headlen)
            {
                return false;
            }

            int len = ntohl(buf->PeekInt32());
            if (buf->ReadableBytes() < len + _headlen)
            {
                return false;
            }

            return true;
        }

        // 序列化
        virtual std::string Serialization(const BaseMessage::Ptr &mes) override
        {
            //|len|mtype|idlen|id|body|
            std::string body = mes->Serialization();
            std::string id = mes->Id();

            // 注意：需要进行主机转网络序列
            int mtype = ::htonl((int)mes->Mtype());
            int idlen = ::htonl(id.size());
            // 注意：这里不能使用mtype、idlen这已经是网络序列了
            int len = _mtlen + _idlen + id.size() + body.size();
            int hlen = ::htonl(len);
            std::string res;
            res.reserve(len + _headlen);
            res.append((char *)&hlen, _headlen);
            res.append((char *)&mtype, _mtlen);
            res.append((char *)&idlen, _idlen);
            res.append(id);
            res.append(body);

            return res;
        }

    private:
        // 固定字段长度
        const int _headlen = 4; // 储存有效载荷的固定长度
        const int _mtlen = 4;   // 储存MType类型的固定长度
        const int _idlen = 4;   // id的固定长度
    };

    class LvProtocolFactory
    {
    public:
        template <typename... Args>
        static BaseProtocol::Ptr create(Args &&...args)
        {
            return std::make_shared<LvProtocol>(std::forward<Args>(args)...);
        }
    };


    class ModuoConnection : public BaseConnection
    {
    public:
        using Ptr = std::shared_ptr<ModuoConnection>;

        ModuoConnection(const BaseProtocol::Ptr &protocol,const  ConnectionPtr &conn)
            : _protocol(protocol),
              _conn(conn)
        {
        }

        // 发送数据
        virtual void Send(const BaseMessage::Ptr &msg) override
        {
            if (_conn->ConnectionStatus())
            {
                LOG(LogLevel::WARNING) << "发送数据";
                std::string body = _protocol->Serialization(msg);
                _conn->Send(body.c_str(),body.size());
            }
            else
            {
                LOG(LogLevel::WARNING) << "连接已失效";
            }
        }

        // 断开连接
        virtual void ShutDown() override
        {
            if (Connected())
                _conn->ShutDwon();
        }

        // 是否连接
        virtual bool Connected() override
        {
            return _conn->ConnectionStatus();
        }

    private:
        BaseProtocol::Ptr _protocol;
        ConnectionPtr _conn;
    };

    class ModuoConnectionFactory
    {
    public:
        template <typename... Args>
        static BaseConnection::Ptr create(Args &&...args)
        {
            return std::make_shared<ModuoConnection>(std::forward<Args>(args)...);
        }
    };

    const int thraed_count = 2;
    class ModuoServer : public BaseServer
    {
    public:
        using Ptr = std::shared_ptr<ModuoServer>;

        // 初始化
        ModuoServer(uint16_t port)
            : _tcpserver(port),
              _protocol(LvProtocolFactory::create())
        {}

        virtual void Start() override
        {
            // 设置回调函数
            _tcpserver.SetThreadCount(thraed_count);
            _tcpserver.SetConnectedCallback(std::bind(&ModuoServer::onConnection, this, std::placeholders::_1));
            _tcpserver.SetMessageCallback(std::bind(&ModuoServer::onMessage, this, std::placeholders::_1,
                                                    std::placeholders::_2));
            _tcpserver.SetClosedCallback(std::bind(&ModuoServer::onClose, this, std::placeholders::_1));                                       
            _tcpserver.Start(); // 开始
        }

        virtual void OpenTimeout(int timeout) override
        {
            _tcpserver.OpenTimeout(timeout);
        }


    private:
        // 作为回调函数 当建立连接时会触发
        void onConnection(const ConnectionPtr &conn)
        {
            if (conn->ConnectionStatus())
            {
                LOG(LogLevel::INFO) << "与客户端连接成功";
                BaseConnection::Ptr bconn = ModuoConnectionFactory::create(_protocol, conn);
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    _conns.insert(std::make_pair(conn, bconn));
                }

                // 如果有连接后的回调函数后就进行调用
                if (_conncallback)
                {
                    _conncallback(bconn);
                }
            }
        }

        // 作为回调函数，当数据准备就绪时会触发
        void onMessage(const ConnectionPtr &conn, Buffer *buf)
        {
            BaseBuffer::Ptr mbuf = BufferFactory::create(buf);
            LOG(LogLevel::DEBUG) << "有新消息来了 : ";

            //_hbs.Modify(conn, t);
            while (1)
            {
                // 数据不足
                if (_protocol->CanProcessed(mbuf) == false)
                {
                    LOG(LogLevel::DEBUG) << "数据不足";

                    // 判断缓冲区是否过大
                    if (mbuf->ReadableBytes() > maxDataSize)
                    {
                        LOG(LogLevel::ERROR) << "缓冲区数据过大";
                        conn->ShutDwon();
                        return;
                    }
                    break;
                }

                // 数据足够
                BaseMessage::Ptr msg;
                bool ret = _protocol->OnMessage(mbuf, msg);
                if (ret == false)
                {
                    LOG(LogLevel::ERROR) << "格式等原因、处理数据失败";
                    conn->ShutDwon();
                    return;
                }

                BaseConnection::Ptr bc;
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        return;
                    }
                    bc = it->second;
                }

                LOG(LogLevel::DEBUG) << "开始处理数据";
                if (_msgcallback)
                {
                    _msgcallback(bc, msg);
                }
            }
        }

        void onClose(const ConnectionPtr &conn)
        {
             
            BaseConnection::Ptr bconn;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                {
                    return;
                }

                bconn = it->second;
                _conns.erase(it);
            }

            if (_closecallback)
            {
                _closecallback(bconn);
            }
            LOG(LogLevel::INFO) << "与客户端断开连接";
            
        }

    private:
        const size_t maxDataSize = (1 << 16);
        BaseProtocol::Ptr _protocol;
        TcpServer _tcpserver;
        std::mutex _mutex;
        std::unordered_map<ConnectionPtr, BaseConnection::Ptr> _conns;
    };

    class ModuoServerFactory
    {
    public:
        template <typename... Args>
        static BaseServer::Ptr create(Args &&...args)
        {
            return std::make_shared<ModuoServer>(std::forward<Args>(args)...);
        }
    };

    class ModuoClient : public BaseClient
    {
    public:
        using Ptr = std::shared_ptr<ModuoClient>;

        ModuoClient(const std::string& ip, uint16_t port)
            :_base_loop(_loopthread.GetLoop()),
             _client(_base_loop),
             _protocol(LvProtocolFactory::create()),
             _ip(ip),
             _port(port)
        {
            sem_init(&_semaphore, 0, 0); 
        }

        virtual bool Send(const BaseMessage::Ptr &mes) override
        {
            if (Connected() == false)
            {
                LOG(LogLevel::DEBUG) << "连接已经断开";
                return false;
            }

            _conn->Send(mes);
            return true;
        }
        virtual void ShutDown() override
        {
            _client.ShutDwon();
        }
        virtual bool Connected() override
        {
            return (_conn && _conn->Connected());
        }
        virtual void Connect() override
        {
            // 设置回调函数
            _client.SetConnectedCallback(std::bind(&ModuoClient::onConnection, this, std::placeholders::_1));
            _client.SetMessageCallback(std::bind(&ModuoClient::onMessage, this, std::placeholders::_1,
                                                 std::placeholders::_2));

            _client.Connect(_ip,_port);
            sem_wait(&_semaphore);
        }
        virtual BaseConnection::Ptr Connection() override
        {
            return _conn;
        }

    private:
        // 作为回调函数 当建立连接时会触发
        void onConnection(const ConnectionPtr &conn)
        {
            if (conn->ConnectionStatus())
            {
                LOG(LogLevel::INFO) << "与服务端连接成功";
                _conn = ModuoConnectionFactory::create(_protocol, conn);
                sem_post(&_semaphore);

                // 如果有连接后的回调函数后就进行调用
                if (_conncallback)
                {
                    _conncallback(_conn);
                }
            }
        }

        // 作为回调函数，当数据准备就绪时会触发
        void onMessage(const ConnectionPtr &conn, Buffer *buf)
        {
            BaseBuffer::Ptr mbuf = BufferFactory::create(buf);
            while (1)
            {
                // 数据不足
                if (_protocol->CanProcessed(mbuf) == false)
                {
                    LOG(LogLevel::DEBUG) << "数据不足";

                    // 判断缓冲区是否过大
                    if (mbuf->ReadableBytes() > maxDataSize)
                    {
                        LOG(LogLevel::ERROR) << "缓冲区数据过大";
                        conn->ShutDwon();
                        return;
                    }

                    break;
                }

                // 数据足够
                BaseMessage::Ptr mes;
                bool ret = _protocol->OnMessage(mbuf, mes);
                if (ret == false)
                {
                    LOG(LogLevel::DEBUG) << "处理数据失败";
                    conn->ShutDwon();
                    return;
                }

                if (_msgcallback)
                {
                    _msgcallback(_conn, mes);
                }
            }
        }
        void onClose(const ConnectionPtr &conn)
        {
            if (_closecallback)
            {
                _closecallback(_conn);
            }
        }


    private:
        const size_t maxDataSize = (1 << 16);
        BaseProtocol::Ptr _protocol;
        BaseConnection::Ptr _conn;
        LoopThread _loopthread;
        EventLoop* _base_loop;
        TcpClient _client;
        std::string _ip;
        uint16_t _port;
        sem_t _semaphore;  // 定义信号量
    };

    class ModuoClientFactory
    {
    public:
        template <typename... Args>
        static BaseClient::Ptr create(Args &&...args)
        {
            return std::make_shared<ModuoClient>(std::forward<Args>(args)...);
        }
    };
};